#!/usr/local/bin/python
# Rob Dennis - Lurchington Q. Delacroix
# Keasby - TV renamer
# Project Homepage: http://code.google.com/p/keasby/

#---Python Import
import re
import os
import sys
import logging
from optparse import OptionParser
from ConfigParser import RawConfigParser

class KeasbyOptions():
    """
    Handles all options for the Keasby Application
    """

    def __init__(self):

        self.parser = OptionParser(version="%prog - beta 1")

        self._populate_parser()
        self._set_defaults()

        config_path=os.path.join("preferences.cfg")

        self._set_prefs_from_config(config_path)

        (self.cl_opts, self.cl_args) = self.parser.parse_args()


    def _set_defaults(self):

        _tmp_dict = {"epnum":"${episode_number}",
                         "season":"${season_number}",
                         "show":"${showname}",
                         "title":"${episode_title}"
                        }

        _template_file = "%(show)s-S%(season)sE%(epnum)s-%(title)s"%_tmp_dict

        _rename_template = os.path.join("${showname}",
                                       "Season ${season_number}",
                                       _template_file)

        self.parser.set_defaults(
                                undo_batch = False,
                                name_batch = False,
                                flush_cache_to_disk = False,
                                overwrite_batch = True,
                                pretend = False,
                                guess_multipart = True,
                                handle_absolute_ordering = False,
                                assume_grouped_numbers = True,
                                grouped_num_split = 2,
                                episode_padding = 2,
                                season_padding = 2,
                                split_episode_char = "-",
                                replace_whitespace = True,
                                allow_partial_info = True,
                                recursive_rename = True,
                                debug = False,
                                verbose = False,
                                show_output = True,
                                input_dir = os.getcwd(),
                                output_dir = os.getcwd(),
                                write_to_folder = False,
                                unattended = False,
                                output_template = _rename_template,
                                manual_showname = None,
                                manual_season = None
                                )

    def _set_prefs_from_config(self, filename):
        pref_config = KeasbyConfigParser()
        pref_config.read(filename)

        for key,value in pref_config.get_dict().items():
            logging.debug("%s = %s (%s)"%(key,value,type(value)))
            self.parser.set_defaults(**{key:value})
            try:
                logging.debug("actual value: %s",
                                self.parser.__dict__["defaults"][key])
            except Exception:
                for parser_key,parser_value in self.parser.__dict__["defaults"].items():
                    logging.debug("%s = %s",parser_key,parser_value)



    def _populate_parser(self):
##        self.parser.add_option( "-u","--makeUndoBatchFile",
##                                dest="undo_batch",action="store_true",
##                                help="enable creation of undo batch file \
##                                [default: %default]")
##
##        self.parser.add_option( "-U","--noMakeUndoBatchFile",
##                                dest="undo_batch",action="store_false",
##                                help="disable creation of undo batch file")
##
##        self.parser.add_option( "-n","--makeNamingBatchFile",
##                                dest="name_batch",action="store_true",
##                                help="enable creation of batch file \
##                                [default: %default]")
##
##        self.parser.add_option( "-N","--noMakeNamingBatchFile",
##                                dest="name_batch",action="store_false",
##                                help="disable creation of batch file")
##
##        self.parser.add_option( "-w","--writeCacheToFile",
##                                dest="flush_cache_to_disk",action="store_true",
##                                help="writes webpage cache to text file in \
##                                dir [default: %default]")
##
##        self.parser.add_option( "-W","--noWriteCacheToFile",
##                                dest="flush_cache_to_disk",
##                                action="store_false",
##                                help="does not write webpage cache to text \
##                                file in dir")
##
##        self.parser.add_option( "--overwriteBatch",dest="overwrite_batch",
##                                action="store_true",
##                                help="always overwrite batch file \
##                                [default: %default]")
##
##        self.parser.add_option( "--appendBatch",
##                                dest="overwrite_batch",action="store_false",
##                                help="only add new entries to batch file")
##
        self.parser.add_option( "-p","--pretend",
                                dest="pretend",action="store_true",
                                help="do not make any changes \
                                [default: %default]")

        self.parser.add_option( "-P","--noPretend",dest="pretend",
                                action="store_false",
                                help="make changes as necessary")

##        self.parser.add_option( "--handleFullRun",
##                                dest="handle_absolute_ordering",
##                                action="store_true",
##                                help="assume absolute numbering scheme \
##                                [default: %default]")
##
##        self.parser.add_option( "--noHandleFullRun",
##                                dest="handle_absolute_ordering",
##                                action="store_false",
##                                help="no special handling for overall \
##                                show order")

        self.parser.add_option( "-a","--assumeGroupedNum",
                                dest="assume_grouped_numbers",
                                action="store_true",
                                help="treats fields like 1005 as both season \
                                and episode number [default: %default]")

        self.parser.add_option( "-A","--noAssumeGroupedNum",
                                dest="assume_grouped_numbers",
                                action="store_false",
                                help="treats fields like 1005 as one number")

        self.parser.add_option( "-g","--groupedNumSplit",
                                dest="grouped_num_split",
                                metavar="NUM",type="int",
                                help="when handling group numbers, split \
                                after NUM places [default: %default]")

        self.parser.add_option( "-G","--episodePadding",dest="episode_padding",
                                metavar="NUM",type="int",
                                help="pads episode number to NUM places \
                                [default: %default]")

        self.parser.add_option( "--seasonPadding",dest="season_padding",
                                metavar="NUM",type="int",
                                help="pads season number to NUM places \
                                [default: %default]")

        self.parser.add_option( "--splitEpisodeChar",dest="split_episode_char",
                                metavar="CHAR",
                                help="Detects numbers split by CHAR as \
                                multi-episodic [default: %default]")

##        self.parser.add_option( "--useUnixNaming",dest="replace_whitespace",
##                                action="store_true",
##                                help="replaces whitespace with '_' \
##                                [default: %default]")
##
##        self.parser.add_option( "--noUseUnixNaming",dest="replace_whitespace",
##                                action="store_false",
##                                help="no special handling for whitespace")
##
##        self.parser.add_option( "-i","--allowPartialInfo",
##                                dest="allow_partial_info",action="store_true",
##                                help="allow partially unknown information in \
##                                new filename [default: %default]")
##
##        self.parser.add_option( "-I","--noAllowPartialInfo",
##                                dest="allow_partial_info",action="store_false",
##                                help="any unknown information will default \
##                                the script to old filename")

        self.parser.add_option( "-r","--recursiveRename",
                                dest="recursive_rename",action="store_true",
                                help="recursively rename files in all \
                                subdirectory [default: %default]")

        self.parser.add_option( "-R","--noRecursiveRename",
                                dest="recursive_rename",action="store_false",
                                help="limit renaming to current directory")

        self.parser.add_option( "-d","--debug",
                                dest="debug",action="store_true",
                                help="print extra debug output \
                                [default: %default]")

        self.parser.add_option( "-D","--noDebug",
                                dest="debug",action="store_false",
                                help="do not print extra debug output")

        self.parser.add_option( "-v","--verbose",dest="verbose",
                                action="store_true",
                                help="print verbose output \
                                [default: %default]")

        self.parser.add_option( "-V","--noVerbose",
                                dest="verbose",action="store_false",
                                help="do not print verbose output")

        self.parser.add_option( "-q","--quiet",
                                dest="show_output",action="store_false",
                                help="squelch all output except errors \
                                [default: %default]")

        self.parser.add_option( "-Q","--noQuiet",
                                dest="show_output",action="store_true",
                                help="print output as normal")

        self.parser.add_option( "-t","--topLevel",
                                dest="input_dir",metavar="PATH",
                                help="top level source hierarchy \
                                [default: current working directory]")

        self.parser.add_option( "-T","--topLevelOutput",
                                dest="output_dir",metavar="PATH",
                                help="top level destination hierarchy \
                                [default: current working directory]")

        self.parser.add_option( "-f","--writeToFolder",
                                dest="write_to_folder",action="store_true",
                                help="enables writing renamed files to \
                                folders, instead of in place \
                                [default: %default]")

        self.parser.add_option( "-F","--noWriteToFolder",
                                dest="write_to_folder",action="store_false",
                                help="disables writing renamed files \
                                to new folder, just within current folder")

        self.parser.add_option( "--unattended",
                                dest="unattended",action="store_true",
                                help="do not prompt for input \
                                [default: %default]")

        self.parser.add_option( "--interactive",
                                dest="unattended",action="store_false",
                                help="require prompts for input")

        self.parser.add_option( "-o","--outputNameString",
                                dest="output_template",metavar="STRING",
                                help="rename filename to formatted STRING \
                                [default: %default]")

        self.parser.add_option( "--showname",dest="manual_showname",
                                help="manually specify the showname \
                                to use [default: %default]")

        self.parser.add_option( "--season",dest="manual_season",
                                help="manually specify the season \
                                to use [default: %default]")


    def get_options(self):
        """return parsed command line"""
        return self.parser.parse_args()

    def echo(self,opt):
        appendListFlag=False
        printOption=""

        for option in str(opt).split(","):
            if not appendListFlag:
                if re.search("(?<=^{).*",option):
                    option=re.search("(?<=^{).*",option).group(0)
                if re.search(".*(?<=}$)",option):
                    option=re.search(".*(?=}$)",option).group(0)
                if re.search(": \[",option):
                    appendListFlag=True
                    printOption=option
                else:
                    printOption=option
                    logging.info(printOption.strip())
            else:
                if re.search("\]$",option):
                    appendListFlag=False
                    logging.info(printOption+option)
                else:
                    printOption=(printOption+","+option).strip()


class KeasbyConfigParser(RawConfigParser):
    """
    Class created for accepting python-formatted code from a config file,
    in a format that's desired for the application
    """

    def _get_best(self,section,option):
        """

        """
        try:
            return eval(self.get(section,option),
                        {"__builtins__":None},
                        {"False":False,
                        "True":True,
                        "re":re,
                        "os":os,
                        "None":None})

        except Exception, error_message:
            logging.warning("error parsing value: %s, %s",
                                self.get(section,option),error_message)

            return self.get(section,option)

    def optionxform(self, optionstr):
        """
        Changes default RawConfigParser behavior to no longer enforce lower
        case for names
        """

        return optionstr

    def get_dict(self,sec_dicts=False):
        """
        intended to return a dictionary which map all the option names
        as the keys. If the options sec_dicts flag is set to True,
        seperate config file [SECTIONS] will have their own key, holding
        a dictionary of the key, value pairs in that section
        """

        tmp_dict={}

        if sec_dicts:
            for sec in self.sections():
                tmp_dict[sec] = {}
                for opt in self.options(sec):
                    tmp_dict[sec][opt] = self._get_best(sec, opt)

        else:
            for sec in self.sections():
                for opt in self.options(sec):
                    tmp_dict[opt] = self._get_best(sec, opt)

        return tmp_dict


class KeasbyOptionsError(Exception):
    """
    Generic KeasbyOptionsError
    """

    pass

class KeasbyConfigError(Exception):
    """
    Generic KeasbyConfigError
    """

    pass

#--- Global Options Instance
keasby_cl = KeasbyOptions()